import javassist.*;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

/**
 * Created by Dell on 2018/8/16.
 */
public class Example2 {

    @Test
    public void testCreateClass() throws Exception {
        String classname = "cc.rico.bean.User";
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.makeClass(classname);

        //添加字段
        CtField idField = CtField.make("private String id;", cc);
        cc.addField(idField);
        CtField nameField = CtField.make("private String name;", cc);
        cc.addField(nameField);

        //添加setter和getter
        //CtMethod.make(src, declaring)内部其实是调用了CtNewMethod.make(src, declaring)
        CtMethod getIdMethod = CtMethod.make("public String getId(){return id;}", cc);
        cc.addMethod(getIdMethod);
        CtMethod setIdMethod = CtMethod.make("public void setId(String id){$0.id=id;}", cc);
        cc.addMethod(setIdMethod);

        CtMethod getNameMethod = CtMethod.make("public String getName(){return name;}", cc);
        cc.addMethod(getNameMethod);
        CtMethod setNameMethod = CtMethod.make("public void setName(String name){$0.name=name;}", cc);
        cc.addMethod(setNameMethod);

        //添加一个有参构造函数
        CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String"), pool.get("java.lang.String")}, cc);
        constructor.setBody("{$0.id=$1;this.name=$2;}");
        cc.addConstructor(constructor);

        //添加一个无参构造函数
        CtConstructor nullArgusconstructor = new CtConstructor(null, cc);
        nullArgusconstructor.setBody("{}");
        cc.addConstructor(nullArgusconstructor);

        // cc.writeFile("d:/src/main/java/cc/rico/javassist");
        //调用了toClass之后，就不能再修改了。此时jvm中是存在这个类的字节码
        Class finalClass = cc.toClass();

        //反射使用
//        Class clz = cc.toClass();
        Class<?> clz = Class.forName(classname);
        Object obj = clz.getConstructor(String.class, String.class).newInstance("100", "李四");
        System.out.println(clz.getMethod("getId").invoke(obj));
        System.out.println(clz.getMethod("getName").invoke(obj));

    }
}
